<?php

namespace W3;

/**
 * 视图类负责将输出展示。
 * 它提供了在渲染时管理视图数据和将数据插入视图模板的函数。
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class View
{
    /**
     * 模板文件所在目录 注意以斜杠结束
     *
     * @var string
     */
    public $path;

    /**
     * 模板文件扩展名
     *
     * @var string
     */
    public $extension = '.php';

    /**
     * 用于存储模板变量
     *
     * @var array
     */
    protected $vars = [];

    /**
     * 模板文件路径
     *
     * @var string
     */
    private $template;

    /**
     * 单例句柄
     *
     * @access protected
     * @var View
     */
    protected static $_instance;
	
    /**
     * 单例实例
     *
     * @return View
     */
    public static function instance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }

    public static function make($path = '.')
    {
        return new static($path);
    }
	
    /**
     * Constructor.
     *
     * @param string $path Path to templates directory
     */
    public function __construct($path = '.') 
	{
        $this->path = $path;
    }

    /**
     * 获取模板变量
     *
     * @param string $key Key
     * @return mixed Value
     */
    public function get($key) 
	{
        return isset($this->config[$key]) ? $this->config[$key] : null;
    }

    /**
     * 设置模板变量
     *
     * @param mixed $key Key
     * @param string $value Value
     */
    public function set($key, $value = null) 
	{
        if (is_array($key) || is_object($key)) {
            foreach ($key as $k => $v) 
			{
                $this->config[$k] = $v;
            }
        }
        else {
            $this->config[$key] = $value;
        }
    }

    /**
     * 检查是否设置了模板变量
     *
     * @param string $key Key
     * @return boolean If key exists
     */
    public function has($key) 
	{
        return isset($this->config[$key]);
    }

    /**
     * 取消设置模板变量。如果没有传入任何键，请清除所有变量
     *
     * @param string $key Key
     */
    public function clear($key = null) 
	{
        if (is_null($key)) {
            $this->config = [];
        }
        else {
            unset($this->config[$key]);
        }
    }

    /**
     * 渲染内容输出
     *
     * @param string $file Template file
     * @param array $data Template data
     * @throws \Exception If template not found
     */
    public function render($file, $data = null) 
	{
        $this->template = $this->template($file);

        if (!file_exists($this->template)) {
            throw new Exception("Template file not found: {$this->template}.");
        }

        if (is_array($data)) {
            $this->config = array_merge($this->config, $data);
        }

        extract($this->config);

        include $this->template;
    }

    /**
     * 获取模板的输出
     *
     * @param string $file Template file
     * @param array $data Template data
     * @return string Output of template
     */
    public function fetch($file, $data = null) 
	{
        ob_start();

        $this->render($file, $data);
        $output = ob_get_clean();

        return $output;
    }

    /**
     * 检查模板文件是否存在.
     *
     * @param string $file Template file
     * @return bool Template file exists
     */
    public function exists($file) 
	{
        return file_exists($this->template($file));
    }

    /**
     * 获取模板文件的完整路径.
     *
     * @param string $file Template file
     * @return string Template file location
     */
    public function template($file) 
	{
        $ext = $this->extension;

        if (!empty($ext) && (substr($file, -1 * strlen($ext)) != $ext)) {
            $file .= $ext;
        }

        if ((substr($file, 0, 1) == '/')) {
            return $file;
        }
        
        return $this->path.'/'.$file;
    }

    /**
     * 显示转义输出.
     *
     * @param string $str String to escape
     * @return string Escaped string
     */
    public function e($str) 
	{
        echo htmlentities($str);
    }
}

